package com.febs.security.code.img;

import com.febs.common.domain.FebsConstant;
import com.febs.common.domain.constant.ImageTypeConstant;
import com.febs.common.helper.StringRedisHelper;
import com.febs.security.code.ValidateCode;
import com.febs.security.code.ValidateCodeGenerator;
import com.febs.security.exception.ValidateCodeException;
import com.febs.security.properties.FebsSecurityProperties;
import com.febs.security.properties.ImageCodeProperties;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.ServletWebRequest;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.json.JSONUtil;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2021/6/18
 */
@Service("imageCodeGenerator")
public class ImageCodeGenerator implements ValidateCodeGenerator {

    @Value("${" + FebsSecurityProperties.ENABLE_REDIS_CACHE + "}")
    private boolean enableRedisCache;

    @Resource
    private SessionStrategy sessionStrategy;

    @Resource
    private FebsSecurityProperties securityProperties;

    private StringRedisHelper redisHelper;

    @Autowired(required = false)
    public void setRedisHelper(StringRedisHelper redisHelper) {
        this.redisHelper = redisHelper;
    }

    @Override
    public ValidateCode createCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        ImageCodeProperties imageProperties = securityProperties.getCode().getImage();
        String key = request.getSession().getId();

        if (StringUtils.isBlank(key)) {
            throw new ValidateCodeException("验证码key不能为空");
        }

        setHeader(response, imageProperties.getType());

        Captcha captcha = createCaptcha(imageProperties);
        String codeKey = FebsConstant.CACHE_KEY_TOKEN_PREFIX + key;
        ValidateCode validateCode = new ValidateCode(StringUtils.lowerCase(captcha.text()), imageProperties.getExpireIn());
        if (enableRedisCache) {
            redisHelper.setEx(codeKey, JSONUtil.toJsonStr(validateCode), imageProperties.getExpireIn(), TimeUnit.SECONDS);
        } else {
            sessionStrategy.setAttribute(new ServletWebRequest(request), codeKey, JSONUtil.toJsonStr(validateCode));
        }
        captcha.out(response.getOutputStream());
        return validateCode;
    }

    private Captcha createCaptcha(ImageCodeProperties code) {
        Captcha captcha;
        if (StringUtils.equalsIgnoreCase(code.getType(), ImageTypeConstant.GIF)) {
            captcha = new GifCaptcha(code.getWidth(), code.getHeight(), code.getLength());
        } else {
            captcha = new SpecCaptcha(code.getWidth(), code.getHeight(), code.getLength());
        }
        captcha.setCharType(code.getCharType());
        return captcha;
    }

    private void setHeader(HttpServletResponse response, String type) {
        if (StringUtils.equalsIgnoreCase(type, ImageTypeConstant.GIF)) {
            response.setContentType(MediaType.IMAGE_GIF_VALUE);
        } else {
            response.setContentType(MediaType.IMAGE_PNG_VALUE);
        }
        response.setHeader(HttpHeaders.PRAGMA, "No-cache");
        response.setHeader(HttpHeaders.CACHE_CONTROL, "No-cache");
        response.setDateHeader(HttpHeaders.EXPIRES, 0L);
    }
}
